/*
MIT License

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo
*/

#ifndef simodo_interpret_StackOfNames
#define simodo_interpret_StackOfNames

/*! \file StackOfNames.h
    \brief Интерфейс держателя семантических правил
*/

#include "simodo/interpret/StackOfNames_interface.h"
#include "simodo/variable/VariableStack.h"

#include <vector>
#include <string>

namespace simodo::interpret
{
    struct BoundInfo
    {
        BoundScope              type;
        size_t                  ref_to_stack;
        boundary_mark_t         mark;
        variable::Variable      accumulator;
    };

    /*!
     * \brief The StackOfNames class
     */
    class StackOfNames : public StackOfNames_interface
    {
        variable::VariableStack     _stack;
        std::vector<BoundInfo>      _boundaries;
        std::vector<name_index_t>   _globals;

    // StackOfNames_interface
    public:
        virtual name_index_t        push(const variable::Variable & name) override;
        virtual name_index_t        pushRef(const variable::Variable & v, 
                                            const inout::TokenLocation & location, 
                                            const variable::VariableSet_t & spec = {}) override;
        virtual name_index_t        top(size_t depth=0) const override;
        virtual name_index_t        index_over_top() const override;
        virtual void                pop(size_t depth=1) override;
        virtual void                erase(name_index_t name_index) override;

        virtual name_index_t        find(const std::u16string & name, BoundScope scope=BoundScope::Global) const override;
        virtual variable::Variable &variable(name_index_t name_index) override;
        virtual const variable::Variable & 
                                    variable(name_index_t name_index) const override;
        virtual void                setName(name_index_t name_index, const std::u16string & new_name) override;
        virtual bool                addGlobal(name_index_t name_index) override;

        virtual boundary_index_t    startBoundary(BoundScope type=BoundScope::Local, boundary_mark_t mark=UNMARKED_BOUNDARY) override;
        virtual void                setBoundaryToGlobal(boundary_index_t bound_index) override;
        virtual bool                clearBoundary(boundary_index_t bound_index) override;
        virtual std::pair<name_index_t,name_index_t>
                                    boundaryLowAndTop(boundary_index_t bound_index) const override;
        virtual boundary_index_t    findNearestMarkedBoundary(boundary_mark_t mark, BoundScope type=BoundScope::Local) const override;
        virtual std::pair<boundary_mark_t,BoundScope> 
                                    getTopBoundaryMarkAndScope() const override;
        virtual variable::Variable &accumulator() override { return _boundaries.back().accumulator; }

        virtual variable::VariableSetWrapper_mutable
                                    makeVariableSetWrapper() override;
        virtual std::shared_ptr<variable::Object> 
                                    convertToObject(boundary_index_t bound_index) override;
        virtual void                fillFromObject(std::shared_ptr<variable::Object> obj) override;
        virtual const std::vector<name_index_t> & 
                                    globals() const override { return _globals; }
        
        virtual bool                isRecursiveCalls() const override;

        virtual std::vector<boundary_index_t> getFunctionBounds() const override;
        virtual std::vector<name_index_t> getFrameLocals(boundary_index_t frame_index) const override;

    public:
        const std::vector<BoundInfo> & boundaries() const { return _boundaries; }
        std::vector<name_index_t> & globals() { return _globals; }

    protected:
        name_index_t                findGlobal(const std::u16string & name) const;
    };

}

#endif // simodo_interpret_StackOfNames
